/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/common.hpp>
#include <dependencies/includes/ink_renderer_interface.h>
#include <journal/common/automation_service_interfaces.h>
#include <journal/views/interfaces.h>
#include <journal/models/interfaces.h>

namespace journal { namespace services { namespace automation {

namespace bs = baja::storage;
namespace bi = baja::ink;
namespace jv = journal::view;

#ifdef DEFINE_STROKE
#undef DEFINE_STROKE
#endif

#define DEFINE_STROKE(x) \
    strokes.push_back(x);

#ifdef DEFINE_SYMBOL
#undef DEFINE_SYMBOL
#endif

#define DEFINE_SYMBOL(symbol, dangling) \
    normalizeSymbolPosition(strokes, dangling); \
    _symbolsMap[symbol] = strokes;\
    strokes.clear();


// used for model based recording
struct symbol_strokes
{
    journal::constants::ink::ink_color color;
    b::float32 width;
    b::uint32 count;
    bi::ink_point* points;
};

class automation_service :
    public iautomation_service,
    public std::enable_shared_from_this<iautomation_service>
{
public:
    automation_service();

    static std::shared_ptr<iautomation_service> create();

    // iautomation_service
    void registerRootView(
        std::weak_ptr<baja::ibase> notebookView);

    bool inProgress();

    void showCreditsAsync();
    void runEnabledTestsAsync();

    void dumpRecordedData();

private:

    struct raiiBool
    {
        bool* _v;
        raiiBool(bool* v) : _v(v)
        {}
        ~raiiBool()
        { *_v = false; }
    };

    struct symbol_context
    {
        b::Boolean default;
        b::float32 x;
        b::float32 y;
        b::float32 scale;

        symbol_context() :
            default(true),
            x(0.0f),
            y(0.0f),
            scale(1.0f)
        {}
    };

    std::vector<std::wstring> _testSymbols;

    bool _inProgress;

    std::map<std::wstring, std::vector<symbol_strokes>> _symbolsMap;

    std::weak_ptr<journal::view::inotebook> _notebookView;

    void sleep(b::uint32 milliSeconds);

    std::shared_ptr<view::iink_surface> getInkSurface(
        const std::shared_ptr<view::ipage>& page);

    b::uint32 fillPageWithStrokes(
        const std::shared_ptr<journal::view::inotebook>& notebookView,
        const b::uint32& pageId,
        const b::wchar* text,
        const b::uint32& textIndex,
        const b::uint32& targetStrokeCount,
        const b::uint32& postSymbolPause,
        const b::uint32& fontSize,
        const b::uint32& fontThickness);

    void fillPageWithPhotos(
        const std::shared_ptr<journal::view::inotebook>& notebookView,
        const b::uint32& pageId);

    void addPhoto(
        const std::shared_ptr<journal::view::inotebook>& notebookView,
        const b::uint32& pageId,
        const std::wstring& fileName,
        const b::float32& angle,
        const b::float32& x,
        const b::float32& y,
        const b::float32& scale
        );

    void addPhoto(
        const std::shared_ptr<journal::view::inotebook>& notebookView,
        const b::uint32& pageId,
        const std::shared_ptr<bs::istorage_file>& photoFile,
        const b::float32& angle,
        const b::float32& x,
        const b::float32& y,
        const b::float32& scale
        );

    void buildAlphabetSymbols();
    void buildJorgeSymbol();
    void buildEricSymbol();
    void buildAlanSymbol();
	void buildJulioSymbol();
    void buildGeorgeSymbol();
    void buildJorgeSketch0Symbol();
    void buildJorgeSketch1Symbol();

    static void normalizeSymbolPosition(
        const std::vector<symbol_strokes>& strokes,
        const bool& dangling);

    void inkSymbol(
        const std::wstring& symbol,
        const symbol_context& context,
        const std::shared_ptr<view::iink_surface>& inkSurface);

    void getSymbolStrokes(
        std::wstring symbol,
        std::vector<symbol_strokes>& strokes);

    const b::wchar* getTestText();
    const b::wchar* getTestText2();

    std::wstring deviceTypeString(a::device_type dt);
    std::wstring pointerEventString(a::pointer_event_type pe);
    std::wstring keyModifiersString(a::key_modifiers km);
    std::wstring colorString(b::uint32 c);

    void showCredits();
    void runEnabledTests();
    void runPageStressTest(std::shared_ptr<journal::view::inotebook> notebookView);
    void runStrokeStressTest(std::shared_ptr<journal::view::inotebook> notebookView);
    void replayInNewPage();

};

std::shared_ptr<iautomation_service> createAutomationService();

}}} // journal::services::automation

